
const mat4 = cc.vmath.mat4;
const vec3 = cc.vmath.vec3;


let _vec3_temp_2 = vec3.create();

let _matView = mat4.create();
let _matProj = mat4.create();
let _matViewProj = mat4.create();
let _matInvViewProj = mat4.create();


cc.Class({
    extends: cc.Camera,
    editor: CC_EDITOR && {
        menu: 'i18n:MAIN_MENU.component.others/Camera',
        inspector: 'packages://inspector/inspectors/comps/camera.js',
        executeInEditMode: false
    },

    /*====================================================================================================*/
    /**
     * 3d屏幕坐标到世界坐标的映射
     * @param {vec3} screnn_pos
     *
     /*====================================================================================================*/
    MyScreenToWorld: function (screen_pos) {
        let out = cc.v3();
        let _camera = this._camera;

        let width = cc.game.canvas.width / cc.view._scaleX;
        let height = cc.game.canvas.height / cc.view._scaleY;

        var aspect = width / height;

        let rect = this.rect;
        let cameraNode = this.node;
        var cx = rect.x * width;
        var cy = rect.y * height;
        var cw = rect.width * width;
        var ch = rect.height * height;

        let fov = Math.PI * 60 / 180;
        let near = this.nearClip;
        let far = this.farClip;

        cameraNode.getWorldRT(_matView);
        mat4.invert(_matView, _matView);

        mat4.perspective(_matProj, fov, aspect, near, far);

        mat4.mul(_matViewProj, _matProj, _matView);
        mat4.invert(_matInvViewProj, _matViewProj);

        //在远裁剪面的世界坐标
        vec3.set(out,
            2 * (screen_pos.x - cx) / cw - 1,
            2 * (screen_pos.y - cy) / ch - 1,
            1,
        );
        vec3.transformMat4(out, out, _matInvViewProj);

        cameraNode.getWorldPosition(_vec3_temp_2);

        out = this._LineToWorldPlane(_vec3_temp_2, out);

        return cc.v2(out.x, out.y);
    },

    /*====================================================================================================*/
    /**
     * 3d世界坐标到屏幕坐标的映射
     *
     /*====================================================================================================*/

    MyWorldToScreen: function (world_pos) {
        let out = cc.v3();
        let _camera = this._camera;

        let width = cc.game.canvas.width / cc.view._scaleX;
        let height = cc.game.canvas.height / cc.view._scaleY;


        var aspect = width / height;

        let rect = this.rect;
        let cameraNode = this.node;
        var cx = rect.x * width;
        var cy = rect.y * height;
        var cw = rect.width * width;
        var ch = rect.height * height;


        cameraNode.getWorldRT(_matView);
        mat4.invert(_matView, _matView);

        let fov = Math.PI * 60 / 180;
        let near = this.nearClip;
        let far = this.farClip;

        mat4.perspective(_matProj, fov, aspect, near, far);
        mat4.mul(_matViewProj, _matProj, _matView);

        vec3.transformMat4(out, world_pos, _matViewProj);

        out.x = cx + .5 * (out.x + 1) * cw;
        out.y = cy + .5 * (out.y + 1) * ch;

        return cc.v2(out.x, out.y);
    },
    /*====================================================================================================*/
    /**
     * 空间射线与世界物体平面的交点.推导过程如下
     * (p - p0) * n = 0
     * P = l0 + t * d_normalize
     * t = (p0 - l0) * n / d_normalize * n
     *
     * 世界物体平面为z=0, 平行于世界x,y轴的平面
     *
     * @param l0 向量起点
     * @param l1 向量终点
     *
     /*====================================================================================================*/
    _LineToWorldPlane(l0, l1) {
        let p0 = cc.v3(0, 0, 0);
        let n = cc.v3(0, 0, 1);

        let _d = cc.v3();
        vec3.sub(_d, p0, l0);

        let d = cc.v3();
        vec3.sub(d, l1, l0);
        vec3.normalize(d, d);

        let t = vec3.dot(_d, n) / vec3.dot(d, n);
        let _p = cc.v3();
        vec3.scale(_p, d, t);

        let p = cc.v3();
        vec3.add(p, _p, l0);
        return p;
    },

});
